package com.powernode.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.http.HttpStatus;
import com.alibaba.fastjson2.JSON;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.AlipayConfig;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.domain.AlipayTradeWapPayModel;
import com.alipay.api.internal.util.AlipaySignature;
import com.alipay.api.request.AlipayTradeWapPayRequest;
import com.alipay.api.response.AlipayTradeWapPayResponse;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.powernode.component.LoginUserHolder;
import com.powernode.config.AlipayConfigConstant;
import com.powernode.dto.Result;
import com.powernode.entity.Order;
import com.powernode.entity.OrderItem;
import com.powernode.enums.OrderStatus;
import com.powernode.enums.TradeStatus;
import com.powernode.exception.BizException;
import com.powernode.service.AliPayService;
import com.powernode.service.OrderItemService;
import com.powernode.service.OrderService;
import lombok.SneakyThrows;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import javax.servlet.http.HttpServletResponse;
import java.io.PrintWriter;
import java.util.Map;
import java.util.Set;

@Service
public class AliPayServiceImpl implements AliPayService {

    @Autowired
    private OrderService service;
    @Autowired
    private OrderItemService itemService;
    @Autowired
    private LoginUserHolder holder;

    private AlipayClient alipayClient;

    /**
     * AlipayClient初始化
     */
    @PostConstruct
    public void init(){
        this.alipayClient = new DefaultAlipayClient(
                AlipayConfigConstant.SERVER_URL,
                AlipayConfigConstant.APPID,
                AlipayConfigConstant.PRIVATE_KEY,
                AlipayConfigConstant.FORMAT,
                AlipayConfigConstant.CHARSET,
                AlipayConfigConstant.ALIPAY_PUBLIC_KEY,
                AlipayConfigConstant.SIGN_TYPE
        );
    }

    /**
     * 跳转到支付页面（手机网页支付）
     */
    @SneakyThrows
    @Override
    public Result toPayWap(Long orderId) {
        // 根据订单id获取订单
        Order order = service.getById(orderId);
        // 如果订单不存在返回错误信息
        if (order == null) {
            return Result.failure(HttpStatus.HTTP_NOT_FOUND,"订单不存在");
        }
        // 判断订单商品是否存在
        if (!itemService.lambdaQuery().eq(OrderItem::getOrderId, orderId).exists()) {
            // 不存在返回错误信息
            return Result.failure(HttpStatus.HTTP_NOT_FOUND,"订单商品不存在");
        }
        // 支付请求对象
        AlipayTradeWapPayRequest payRequest = new AlipayTradeWapPayRequest();
        // 支付参数对象
        AlipayTradeWapPayModel payModel = new AlipayTradeWapPayModel();
        // 设置订单编号
        payModel.setOutTradeNo(String.valueOf(orderId));
        // 设置支付总金额
        payModel.setTotalAmount(String.valueOf(order.getTotalPrice()));
        // 设置支付主题
        payModel.setSubject(order.getDesc());
        // 设置支付类型：QUICK_WAP_WAY是手机网站支付，QUICK_MSECURITY_PAY是手机app支付，FAST_INSTANCE_TRADE_PAY是电脑网站支付
        payModel.setProductCode("QUICK_WAP_WAY");

        // 设置支付请求的参数
        payRequest.setBizModel(payModel);

        // 设置支付的同步回调
        payRequest.setReturnUrl(AlipayConfigConstant.RETURN_URL);
        // 设置支付的异步通知
        payRequest.setNotifyUrl(AlipayConfigConstant.NOTIFY_URL);

        // 发起支付请求，跳转到支付页面，获取支付响应对象
        try {
            AlipayTradeWapPayResponse payResponse = alipayClient.pageExecute(payRequest);
            return Result.success(payResponse.getBody());
        } catch (AlipayApiException e) {
            e.printStackTrace();
            return Result.failure(HttpStatus.HTTP_INTERNAL_ERROR,e.getMessage());
        }
    }

    /**
     * 支付同步回调
     */
    @SneakyThrows
    @Override
    public void success(Map<String, String> params) {

        // 验证签名是否合法
        boolean rsaCheck = AlipaySignature.rsaCheckV1(params,
                AlipayConfigConstant.ALIPAY_PUBLIC_KEY, AlipayConfigConstant.CHARSET, AlipayConfigConstant.SIGN_TYPE);
        if (rsaCheck) {
            /**
             * 1.商家需要验证该通知数据中的 out_trade_no 是否为商家系统中创建的订单号。
             * 2.判断 total_amount 是否确实为该订单的实际金额（即商家订单创建时的金额）。
             * 3.校验通知中的 seller_id（或者 seller_email) 是否为 out_trade_no 这笔单据对应的操作方（有的时候，一个商家可能有多个 seller_id/seller_email）。
             * 4.验证 app_id 是否为该商家本身。
             * 上述1、2、3、4有任何一个验证不通过，则表明同步校验结果是无效的，只有全部验证通过后，才可以认定买家付款成功。
             */
            // 1.
            Order order = service.getOne(new LambdaQueryWrapper<Order>().eq(Order::getUserId, holder.getLoginUserId()));
            if ( ! params.get("out_trade_no").equals (String.valueOf(order.getOrderId()))) {
                throw new BizException(HttpStatus.HTTP_NOT_FOUND,"订单不存在");
            }
            // 2.
            if (! params.get("total_amount").equals(String.valueOf(order.getTotalPrice()))){
                throw new BizException(HttpStatus.HTTP_BAD_REQUEST,"订单金额不一致，请重新确认");
            }
            // 3. 4. TODO 上线后申请商家id
        }

    }

    @SneakyThrows
    @Override
    public void notify(Map<String, String> params) {
        // 验证签名是否合法
        boolean rsaCheck = AlipaySignature.rsaCheckV1(params,
                AlipayConfigConstant.ALIPAY_PUBLIC_KEY, AlipayConfigConstant.CHARSET, AlipayConfigConstant.SIGN_TYPE);
        if (rsaCheck) {
            // 订单号
            String orderId = params.get("out_trade_no");
            // 支付宝交易凭证号
            String tradeNo = params.get("trade_no");
            // 订单名称
            String tradeName = params.get("subject");
            // 交易金额
            String totalAmount = params.get("total_amount");
            // 交易状态
            String tradeStatus = params.get("trade_status");
            // 买家支付宝账号
            String buyerLogonId = params.get("buyer_logon_id");
            /**
             * 1.商家需要验证该通知数据中的 out_trade_no 是否为商家系统中创建的订单号。
             * 2.判断 total_amount 是否确实为该订单的实际金额（即商家订单创建时的金额）。
             * 3.校验通知中的 seller_id（或者 seller_email) 是否为 out_trade_no 这笔单据对应的操作方（有的时候，一个商家可能有多个 seller_id/seller_email）。
             * 4.验证 app_id 是否为该商家本身。
             * 上述1、2、3、4有任何一个验证不通过，则表明同步校验结果是无效的，只有全部验证通过后，才可以认定买家付款成功。
             */
            // 1.
//            Order order = service.getOne(new LambdaQueryWrapper<Order>().eq(Order::getUserId, holder.getLoginUserId()));
//            if ( ! params.get("out_trade_no").equals (String.valueOf(order.getOrderId()))) {
//                throw new BizException(HttpStatus.HTTP_NOT_FOUND,"订单不存在");
//            }
//            // 2.
//            if (! params.get("total_amount").equals(String.valueOf(order.getTotalPrice()))){
//                throw new BizException(HttpStatus.HTTP_BAD_REQUEST,"订单金额不一致，请重新确认");
//            }
            // 3. 4. TODO 上线后申请商家id
            // 如果交易成功，更改订单状态
            Order order = service.getById(orderId);
            if (tradeStatus.equals(TradeStatus.TRADE_SUCCESS.getValue())){
                order.setStatus(OrderStatus.STATUS_2.getCode());
                service.updateById(order);
                // TODO 设计交易记录表，将交易成功后传过来的信息记录下来（如果是上线后，商品走支付的生产环境，支付宝有专门的客户端记录支付信息）
            }
        }
    }
}
